﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;

namespace Jarvis.Rules
{
    [Serializable()]
    public class RuleComponent : ISerializable
    {
        public const Int16 DoesEqual = 0;
        public const Int16 NotEqual = 1;
        public const Int16 Contains = 2;
        public const Int16 NotContains = 3;
        public const Int16 LessOrEqual = 4;
        public const Int16 Less = 5;
        public const Int16 GreaterOrEqual = 6;
        public const Int16 Greater = 7;

        public String Field { get; set; }
        public Int16 Operation { get; set; }
        public object Value { get; set; }

        public override String ToString()
        {
            return Field + " =" + Operation + "= " + Value;
        }

        public RuleComponent()
        {
            Field = "Foo";
            Operation = DoesEqual;
            Value = "Bar";
        }

        public RuleComponent(SerializationInfo info, StreamingContext ctxt)
        {
            this.Field = (String) info.GetValue("Field", typeof(String));
            this.Operation = (Int16)info.GetValue("Operation", typeof(Int16));
            this.Value = (object) info.GetValue("Value", typeof(object));
        }
        
        public void GetObjectData(SerializationInfo info, StreamingContext ctxt)
        {
            info.AddValue("Field", this.Field);
            info.AddValue("Operation", this.Operation);
            info.AddValue("Value", this.Value);
        }

        public Boolean IsMatch(Dictionary<String, object> state)
        {
            try
            {
                object stateValue = state[Field];

                if (stateValue != null)
                {
                    if (stateValue is String)
                    {
                        String stringValue = (stateValue as String);

                        switch (Operation)
                        {
                            case DoesEqual:
                                return stringValue.Equals(Value.ToString());
                            case NotEqual:
                                return !stringValue.Equals(Value.ToString());
                            case Contains:
                                return (stringValue.IndexOf(Value.ToString()) != -1);
                            case NotContains:
                                return (stringValue.IndexOf(Value.ToString()) == -1);
                            default:
                                break;
                        }
                    }
                    else if (stateValue is Double)
                    {
                        Double doubleValue = (Double) stateValue;

                        Double ruleValue = Convert.ToDouble(this.Value.ToString());

                        switch (Operation)
                        {
                            case DoesEqual:
                                return (doubleValue == ruleValue);
                            case NotEqual:
                                return (doubleValue != ruleValue);
                            case LessOrEqual:
                                return (doubleValue <= ruleValue);
                            case Less:
                                return (doubleValue < ruleValue);
                            case GreaterOrEqual:
                                return (doubleValue >= ruleValue);
                            case Greater:
                                return (doubleValue > ruleValue);
                            default:
                                break;
                        }
                    }
                    else if (stateValue is List<object>)
                    {
                        List<object> listValue = (stateValue as List<object>);

                        switch (Operation)
                        {
                            case Contains:
                                return (listValue.IndexOf(Value) != -1);
                            case NotContains:
                                return (listValue.IndexOf(Value) == -1);
                            default:
                                break;
                        }
                    }
                }
            }
            catch (Exception) // e)
            {
                // Console.WriteLine("RULE COMPONENT EXCEPTION [" + Field + "]: " + e);
            }

            return false;
        }
    }
}
